﻿// Copyright (c) .NET Foundation. All rights reserved.
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Threading.Tasks;
using Microsoft.EntityFrameworkCore.TestModels.Northwind;
using Microsoft.EntityFrameworkCore.TestUtilities.Xunit;
using Xunit;

// ReSharper disable InconsistentNaming
// ReSharper disable StringStartsWithIsCultureSpecific
// ReSharper disable StringEndsWithIsCultureSpecific
// ReSharper disable StringCompareIsCultureSpecific.1
// ReSharper disable StringCompareToIsCultureSpecific
// ReSharper disable CompareOfFloatsByEqualityOperator
// ReSharper disable ConditionIsAlwaysTrueOrFalse
// ReSharper disable SpecifyACultureInStringConversionExplicitly
#pragma warning disable RCS1215 // Expression is always equal to true/false.
#pragma warning disable RCS1155 // Use StringComparison when comparing strings.
namespace Microsoft.EntityFrameworkCore.Query
{
    // ReSharper disable once UnusedTypeParameter
    public abstract partial class SimpleQueryTestBase<TFixture>
    {
        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task String_StartsWith_Literal(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactName.StartsWith("M")),
                entryCount: 12);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task String_StartsWith_Identity(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactName.StartsWith(c.ContactName)),
                entryCount: 91);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task String_StartsWith_Column(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactName.StartsWith(c.ContactName)),
                entryCount: 91);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task String_StartsWith_MethodCall(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactName.StartsWith(LocalMethod1())),
                entryCount: 12);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task String_EndsWith_Literal(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactName.EndsWith("b")),
                entryCount: 1);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task String_EndsWith_Identity(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactName.EndsWith(c.ContactName)),
                entryCount: 91);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task String_EndsWith_Column(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactName.EndsWith(c.ContactName)),
                entryCount: 91);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task String_EndsWith_MethodCall(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactName.EndsWith(LocalMethod2())),
                entryCount: 1);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task String_Contains_Literal(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactName.Contains("M")),
                entryCount: 19);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task String_Contains_Identity(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactName.Contains(c.ContactName)),
                entryCount: 91);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task String_Contains_Column(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactName.Contains(c.ContactName)),
                entryCount: 91);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task String_Contains_MethodCall(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactName.Contains(LocalMethod1())),
                entryCount: 19);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task String_Compare_simple_zero(bool isAsync)
        {
            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.Compare(c.CustomerID, "ALFKI") == 0),
                entryCount: 1);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => 0 != string.Compare(c.CustomerID, "ALFKI")),
                entryCount: 90);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.Compare(c.CustomerID, "ALFKI") > 0),
                entryCount: 90);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => 0 >= string.Compare(c.CustomerID, "ALFKI")),
                entryCount: 1);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => 0 < string.Compare(c.CustomerID, "ALFKI")),
                entryCount: 90);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.Compare(c.CustomerID, "ALFKI") <= 0),
                entryCount: 1);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task String_Compare_simple_one(bool isAsync)
        {
            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.Compare(c.CustomerID, "ALFKI") == 1),
                entryCount: 90);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => -1 == string.Compare(c.CustomerID, "ALFKI")));

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.Compare(c.CustomerID, "ALFKI") < 1),
                entryCount: 1);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => 1 > string.Compare(c.CustomerID, "ALFKI")),
                entryCount: 1);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.Compare(c.CustomerID, "ALFKI") > -1),
                entryCount: 91);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => -1 < string.Compare(c.CustomerID, "ALFKI")),
                entryCount: 91);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task String_compare_with_parameter(bool isAsync)
        {
            Customer customer = null;
            using (var context = CreateContext())
            {
                customer = context.Customers.OrderBy(c => c.CustomerID).First();
            }

            ClearLog();

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.Compare(c.CustomerID, customer.CustomerID) == 1),
                entryCount: 90);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => -1 == string.Compare(c.CustomerID, customer.CustomerID)));

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.Compare(c.CustomerID, customer.CustomerID) < 1),
                entryCount: 1);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => 1 > string.Compare(c.CustomerID, customer.CustomerID)),
                entryCount: 1);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.Compare(c.CustomerID, customer.CustomerID) > -1),
                entryCount: 91);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => -1 < string.Compare(c.CustomerID, customer.CustomerID)),
                entryCount: 91);
        }

        [ConditionalTheory(Skip = "Issue #14935. Cannot eval 'where (Compare([c].CustomerID, \"ALFKI\") == 42)'")]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task String_Compare_simple_client(bool isAsync)
        {
            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.Compare(c.CustomerID, "ALFKI") == 42));

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.Compare(c.CustomerID, "ALFKI") > 42));

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => 42 > string.Compare(c.CustomerID, "ALFKI")),
                entryCount: 91);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task String_Compare_nested(bool isAsync)
        {
            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.Compare(c.CustomerID, "M" + c.CustomerID) == 0));

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => 0 != string.Compare(c.CustomerID, c.CustomerID.ToUpper())));

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.Compare(c.CustomerID, "ALFKI".Replace("ALF".ToUpper(), c.CustomerID)) > 0));

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => 0 >= string.Compare(c.CustomerID, "M" + c.CustomerID)),
                entryCount: 51);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => 1 == string.Compare(c.CustomerID, c.CustomerID.ToUpper())));

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.Compare(c.CustomerID, "ALFKI".Replace("ALF".ToUpper(), c.CustomerID)) == -1),
                entryCount: 91);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task String_Compare_multi_predicate(bool isAsync)
        {
            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.Compare(c.CustomerID, "ALFKI") > -1).Where(c => string.Compare(c.CustomerID, "CACTU") == -1),
                entryCount: 11);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.Compare(c.ContactTitle, "Owner") == 0).Where(c => string.Compare(c.Country, "USA") != 0),
                entryCount: 15);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task String_Compare_to_simple_zero(bool isAsync)
        {
            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID.CompareTo("ALFKI") == 0),
                entryCount: 1);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => 0 != c.CustomerID.CompareTo("ALFKI")),
                entryCount: 90);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID.CompareTo("ALFKI") > 0),
                entryCount: 90);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => 0 >= c.CustomerID.CompareTo("ALFKI")),
                entryCount: 1);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => 0 < c.CustomerID.CompareTo("ALFKI")),
                entryCount: 90);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID.CompareTo("ALFKI") <= 0),
                entryCount: 1);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task String_Compare_to_simple_one(bool isAsync)
        {
            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID.CompareTo("ALFKI") == 1),
                entryCount: 90);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => -1 == c.CustomerID.CompareTo("ALFKI")));

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID.CompareTo("ALFKI") < 1),
                entryCount: 1);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => 1 > c.CustomerID.CompareTo("ALFKI")),
                entryCount: 1);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID.CompareTo("ALFKI") > -1),
                entryCount: 91);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => -1 < c.CustomerID.CompareTo("ALFKI")),
                entryCount: 91);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task String_compare_to_with_parameter(bool isAsync)
        {
            Customer customer = null;
            using (var context = CreateContext())
            {
                customer = context.Customers.OrderBy(c => c.CustomerID).First();
            }

            ClearLog();

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID.CompareTo(customer.CustomerID) == 1),
                entryCount: 90);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => -1 == c.CustomerID.CompareTo(customer.CustomerID)));

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID.CompareTo(customer.CustomerID) < 1),
                entryCount: 1);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => 1 > c.CustomerID.CompareTo(customer.CustomerID)),
                entryCount: 1);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID.CompareTo(customer.CustomerID) > -1),
                entryCount: 91);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => -1 < c.CustomerID.CompareTo(customer.CustomerID)),
                entryCount: 91);
        }

        [ConditionalTheory(Skip = "Issue #14935. Cannot eval 'where ([c].CustomerID.CompareTo(\"ALFKI\") == 42)'")]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task String_Compare_to_simple_client(bool isAsync)
        {
            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID.CompareTo("ALFKI") == 42));

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID.CompareTo("ALFKI") > 42));

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => 42 > c.CustomerID.CompareTo("ALFKI")),
                entryCount: 91);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task String_Compare_to_nested(bool isAsync)
        {
            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID.CompareTo("M" + c.CustomerID) == 0));

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => 0 != c.CustomerID.CompareTo(c.CustomerID.ToUpper())));

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID.CompareTo("ALFKI".Replace("ALF".ToUpper(), c.CustomerID)) > 0));

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => 0 >= c.CustomerID.CompareTo("M" + c.CustomerID)),
                entryCount: 51);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => 1 == c.CustomerID.CompareTo(c.CustomerID.ToUpper())));

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID.CompareTo("ALFKI".Replace("ALF".ToUpper(), c.CustomerID)) == -1),
                entryCount: 91);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task String_Compare_to_multi_predicate(bool isAsync)
        {
            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID.CompareTo("ALFKI") > -1).Where(c => c.CustomerID.CompareTo("CACTU") == -1),
                entryCount: 11);

            await AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactTitle.CompareTo("Owner") == 0).Where(c => c.Country.CompareTo("USA") != 0),
                entryCount: 15);
        }

        [ConditionalTheory]
        [InlineData(false, false)]
        [InlineData(true, false)]
        [InlineData(false, true)]
        [InlineData(true, true)]
        public virtual async Task DateTime_Compare_to_simple_zero(bool isAsync, bool compareTo)
        {
            var myDatetime = new DateTime(1998, 5, 4);

            if (compareTo)
            {
                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => c.OrderDate.Value.CompareTo(myDatetime) == 0),
                    entryCount: 3);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => 0 != c.OrderDate.Value.CompareTo(myDatetime)),
                    entryCount: 827);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => c.OrderDate.Value.CompareTo(myDatetime) > 0),
                    entryCount: 8);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => 0 >= c.OrderDate.Value.CompareTo(myDatetime)),
                    entryCount: 822);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => 0 < c.OrderDate.Value.CompareTo(myDatetime)),
                    entryCount: 8);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => c.OrderDate.Value.CompareTo(myDatetime) <= 0),
                    entryCount: 822);
            }
            else
            {
                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => DateTime.Compare(c.OrderDate.Value, myDatetime) == 0),
                    entryCount: 3);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => 0 != DateTime.Compare(c.OrderDate.Value, myDatetime)),
                    entryCount: 827);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => DateTime.Compare(c.OrderDate.Value, myDatetime) > 0),
                    entryCount: 8);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => 0 >= DateTime.Compare(c.OrderDate.Value, myDatetime)),
                    entryCount: 822);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => 0 < DateTime.Compare(c.OrderDate.Value, myDatetime)),
                    entryCount: 8);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => DateTime.Compare(c.OrderDate.Value, myDatetime) <= 0),
                    entryCount: 822);
            }
        }

        [ConditionalTheory]
        [InlineData(false, false)]
        [InlineData(true, false)]
        [InlineData(false, true)]
        [InlineData(true, true)]
        public virtual async Task TimeSpan_Compare_to_simple_zero(bool isAsync, bool compareTo)
        {
            var myDatetime = new DateTime(1998, 5, 4);

            if (compareTo)
            {
                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => c.OrderDate.Value.CompareTo(myDatetime) == 0),
                    entryCount: 3);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => 0 != c.OrderDate.Value.CompareTo(myDatetime)),
                    entryCount: 827);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => c.OrderDate.Value.CompareTo(myDatetime) > 0),
                    entryCount: 8);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => 0 >= c.OrderDate.Value.CompareTo(myDatetime)),
                    entryCount: 822);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => 0 < c.OrderDate.Value.CompareTo(myDatetime)),
                    entryCount: 8);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => c.OrderDate.Value.CompareTo(myDatetime) <= 0),
                    entryCount: 822);
            }
            else
            {
                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => DateTime.Compare(c.OrderDate.Value, myDatetime) == 0),
                    entryCount: 3);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => 0 != DateTime.Compare(c.OrderDate.Value, myDatetime)),
                    entryCount: 827);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => DateTime.Compare(c.OrderDate.Value, myDatetime) > 0),
                    entryCount: 8);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => 0 >= DateTime.Compare(c.OrderDate.Value, myDatetime)),
                    entryCount: 822);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => 0 < DateTime.Compare(c.OrderDate.Value, myDatetime)),
                    entryCount: 8);

                await AssertQuery<Order>(
                    isAsync,
                    cs => cs.Where(c => DateTime.Compare(c.OrderDate.Value, myDatetime) <= 0),
                    entryCount: 822);
            }
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task Int_Compare_to_simple_zero(bool isAsync)
        {
            var orderId = 10250;

            await AssertQuery<Order>(
                isAsync,
                cs => cs.Where(c => c.OrderID.CompareTo(orderId) == 0),
                entryCount: 1);

            await AssertQuery<Order>(
                isAsync,
                cs => cs.Where(c => 0 != c.OrderID.CompareTo(orderId)),
                entryCount: 829);

            await AssertQuery<Order>(
                isAsync,
                cs => cs.Where(c => c.OrderID.CompareTo(orderId) > 0),
                entryCount: 827);

            await AssertQuery<Order>(
                isAsync,
                cs => cs.Where(c => 0 >= c.OrderID.CompareTo(orderId)),
                entryCount: 3);

            await AssertQuery<Order>(
                isAsync,
                cs => cs.Where(c => 0 < c.OrderID.CompareTo(orderId)),
                entryCount: 827);

            await AssertQuery<Order>(
                isAsync,
                cs => cs.Where(c => c.OrderID.CompareTo(orderId) <= 0),
                entryCount: 3);
        }

        protected static string LocalMethod1()
        {
            return "M";
        }

        protected static string LocalMethod2()
        {
            return "m";
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_abs1(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => Math.Abs(od.ProductID) > 10),
                entryCount: 1939);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_abs2(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => Math.Abs(od.Quantity) > 10),
                entryCount: 1547);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_abs3(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => Math.Abs(od.UnitPrice) > 10),
                entryCount: 1677);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_abs_uncorrelated(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => Math.Abs(-10) < od.ProductID),
                entryCount: 1939);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_ceiling1(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => Math.Ceiling(od.Discount) > 0),
                entryCount: 838);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_ceiling2(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => Math.Ceiling(od.UnitPrice) > 10),
                entryCount: 1677);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_floor(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => Math.Floor(od.UnitPrice) > 10),
                entryCount: 1658);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_power(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => Math.Pow(od.Discount, 2) > 0.05f),
                entryCount: 154);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_round(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => Math.Round(od.UnitPrice) > 10),
                entryCount: 1662);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Select_math_round_int(bool isAsync)
        {
            return AssertQuery<Order>(
                isAsync,
                os => os.Where(o => o.OrderID < 10250).Select(
                    o => new
                    {
                        A = Math.Round((double)o.OrderID)
                    }),
                e => e.A);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Select_math_truncate_int(bool isAsync)
        {
            return AssertQuery<Order>(
                isAsync,
                os => os.Where(o => o.OrderID < 10250).Select(
                    o => new
                    {
                        A = Math.Truncate((double)o.OrderID)
                    }),
                e => e.A);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_round2(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => Math.Round(od.UnitPrice, 2) > 100),
                entryCount: 46);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_truncate(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => Math.Truncate(od.UnitPrice) > 10),
                entryCount: 1658);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_exp(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => od.OrderID == 11077).Where(od => Math.Exp(od.Discount) > 1),
                entryCount: 13);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_log10(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => od.OrderID == 11077 && od.Discount > 0).Where(od => Math.Log10(od.Discount) < 0),
                entryCount: 13);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_log(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => od.OrderID == 11077 && od.Discount > 0).Where(od => Math.Log(od.Discount) < 0),
                entryCount: 13);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_log_new_base(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => od.OrderID == 11077 && od.Discount > 0).Where(od => Math.Log(od.Discount, 7) < 0),
                entryCount: 13);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_sqrt(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => od.OrderID == 11077).Where(od => Math.Sqrt(od.Discount) > 0),
                entryCount: 13);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_acos(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => od.OrderID == 11077).Where(od => Math.Acos(od.Discount) > 1),
                entryCount: 25);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_asin(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => od.OrderID == 11077).Where(od => Math.Asin(od.Discount) > 0),
                entryCount: 13);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_atan(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => od.OrderID == 11077).Where(od => Math.Atan(od.Discount) > 0),
                entryCount: 13);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_atan2(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => od.OrderID == 11077).Where(od => Math.Atan2(od.Discount, 1) > 0),
                entryCount: 13);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_cos(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => od.OrderID == 11077).Where(od => Math.Cos(od.Discount) > 0),
                entryCount: 25);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_sin(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => od.OrderID == 11077).Where(od => Math.Sin(od.Discount) > 0),
                entryCount: 13);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_tan(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => od.OrderID == 11077).Where(od => Math.Tan(od.Discount) > 0),
                entryCount: 13);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_sign(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => od.OrderID == 11077).Where(od => Math.Sign(od.Discount) > 0),
                entryCount: 13);
        }

        [ConditionalTheory(Skip = "Issue #14935. Cannot eval 'where (Max([od].OrderID, [od].ProductID) == [od].OrderID)'")]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_max(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => od.OrderID == 11077).Where(od => Math.Max(od.OrderID, od.ProductID) == od.OrderID),
                entryCount: 25);
        }

        [ConditionalTheory(Skip = "Issue #14935. Cannot eval 'where (Min([od].OrderID, [od].ProductID) == [od].ProductID)'")]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_math_min(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => od.OrderID == 11077).Where(od => Math.Min(od.OrderID, od.ProductID) == od.ProductID),
                entryCount: 25);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_guid_newguid(bool isAsync)
        {
            return AssertQuery<OrderDetail>(
                isAsync,
                ods => ods.Where(od => Guid.NewGuid() != default),
                entryCount: 2155);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_string_to_upper(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID.ToUpper() == "ALFKI"),
                entryCount: 1);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_string_to_lower(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID.ToLower() == "alfki"),
                entryCount: 1);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Where_functions_nested(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => Math.Pow(c.CustomerID.Length, 2) == 25),
                entryCount: 91);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task Convert_ToByte(bool isAsync)
        {
            var convertMethods = new List<Expression<Func<Order, bool>>>
            {
                o => Convert.ToByte(Convert.ToByte(o.OrderID % 1)) >= 0,
                o => Convert.ToByte(Convert.ToDecimal(o.OrderID % 1)) >= 0,
                o => Convert.ToByte(Convert.ToDouble(o.OrderID % 1)) >= 0,
                o => Convert.ToByte((float)Convert.ToDouble(o.OrderID % 1)) >= 0,
                o => Convert.ToByte(Convert.ToInt16(o.OrderID % 1)) >= 0,
                o => Convert.ToByte(Convert.ToInt32(o.OrderID % 1)) >= 0,
                o => Convert.ToByte(Convert.ToInt64(o.OrderID % 1)) >= 0,
                o => Convert.ToByte(Convert.ToString(o.OrderID % 1)) >= 0
            };

            foreach (var convertMethod in convertMethods)
            {
                await AssertQuery<Order>(
                    isAsync,
                    os => os.Where(o => o.CustomerID == "ALFKI")
                        .Where(convertMethod),
                    entryCount: 6);
            }
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task Convert_ToDecimal(bool isAsync)
        {
            var convertMethods = new List<Expression<Func<Order, bool>>>
            {
                o => Convert.ToDecimal(Convert.ToByte(o.OrderID % 1)) >= 0,
                o => Convert.ToDecimal(Convert.ToDecimal(o.OrderID % 1)) >= 0,
                o => Convert.ToDecimal(Convert.ToDouble(o.OrderID % 1)) >= 0,
                o => Convert.ToDecimal((float)Convert.ToDouble(o.OrderID % 1)) >= 0,
                o => Convert.ToDecimal(Convert.ToInt16(o.OrderID % 1)) >= 0,
                o => Convert.ToDecimal(Convert.ToInt32(o.OrderID % 1)) >= 0,
                o => Convert.ToDecimal(Convert.ToInt64(o.OrderID % 1)) >= 0,
                o => Convert.ToDecimal(Convert.ToString(o.OrderID % 1)) >= 0
            };

            foreach (var convertMethod in convertMethods)
            {
                await AssertQuery<Order>(
                    isAsync,
                    os => os.Where(o => o.CustomerID == "ALFKI")
                        .Where(convertMethod),
                    entryCount: 6);
            }
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task Convert_ToDouble(bool isAsync)
        {
            var convertMethods = new List<Expression<Func<Order, bool>>>
            {
                o => Convert.ToDouble(Convert.ToByte(o.OrderID % 1)) >= 0,
                o => Convert.ToDouble(Convert.ToDecimal(o.OrderID % 1)) >= 0,
                o => Convert.ToDouble(Convert.ToDouble(o.OrderID % 1)) >= 0,
                o => Convert.ToDouble((float)Convert.ToDouble(o.OrderID % 1)) >= 0,
                o => Convert.ToDouble(Convert.ToInt16(o.OrderID % 1)) >= 0,
                o => Convert.ToDouble(Convert.ToInt32(o.OrderID % 1)) >= 0,
                o => Convert.ToDouble(Convert.ToInt64(o.OrderID % 1)) >= 0,
                o => Convert.ToDouble(Convert.ToString(o.OrderID % 1)) >= 0
            };

            foreach (var convertMethod in convertMethods)
            {
                await AssertQuery<Order>(
                    isAsync,
                    os => os.Where(o => o.CustomerID == "ALFKI")
                        .Where(convertMethod),
                    entryCount: 6);
            }
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task Convert_ToInt16(bool isAsync)
        {
            var convertMethods = new List<Expression<Func<Order, bool>>>
            {
                o => Convert.ToInt16(Convert.ToByte(o.OrderID % 1)) >= 0,
                o => Convert.ToInt16(Convert.ToDecimal(o.OrderID % 1)) >= 0,
                o => Convert.ToInt16(Convert.ToDouble(o.OrderID % 1)) >= 0,
                o => Convert.ToInt16((float)Convert.ToDouble(o.OrderID % 1)) >= 0,
                o => Convert.ToInt16(Convert.ToInt16(o.OrderID % 1)) >= 0,
                o => Convert.ToInt16(Convert.ToInt32(o.OrderID % 1)) >= 0,
                o => Convert.ToInt16(Convert.ToInt64(o.OrderID % 1)) >= 0,
                o => Convert.ToInt16(Convert.ToString(o.OrderID % 1)) >= 0
            };

            foreach (var convertMethod in convertMethods)
            {
                await AssertQuery<Order>(
                    isAsync,
                    os => os.Where(o => o.CustomerID == "ALFKI")
                        .Where(convertMethod),
                    entryCount: 6);
            }
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task Convert_ToInt32(bool isAsync)
        {
            var convertMethods = new List<Expression<Func<Order, bool>>>
            {
                o => Convert.ToInt32(Convert.ToByte(o.OrderID % 1)) >= 0,
                o => Convert.ToInt32(Convert.ToDecimal(o.OrderID % 1)) >= 0,
                o => Convert.ToInt32(Convert.ToDouble(o.OrderID % 1)) >= 0,
                o => Convert.ToInt32((float)Convert.ToDouble(o.OrderID % 1)) >= 0,
                o => Convert.ToInt32(Convert.ToInt16(o.OrderID % 1)) >= 0,
                o => Convert.ToInt32(Convert.ToInt32(o.OrderID % 1)) >= 0,
                o => Convert.ToInt32(Convert.ToInt64(o.OrderID % 1)) >= 0,
                o => Convert.ToInt32(Convert.ToString(o.OrderID % 1)) >= 0
            };

            foreach (var convertMethod in convertMethods)
            {
                await AssertQuery<Order>(
                    isAsync,
                    os => os.Where(o => o.CustomerID == "ALFKI")
                        .Where(convertMethod),
                    entryCount: 6);
            }
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task Convert_ToInt64(bool isAsync)
        {
            var convertMethods = new List<Expression<Func<Order, bool>>>
            {
                o => Convert.ToInt64(Convert.ToByte(o.OrderID % 1)) >= 0,
                o => Convert.ToInt64(Convert.ToDecimal(o.OrderID % 1)) >= 0,
                o => Convert.ToInt64(Convert.ToDouble(o.OrderID % 1)) >= 0,
                o => Convert.ToInt64((float)Convert.ToDouble(o.OrderID % 1)) >= 0,
                o => Convert.ToInt64(Convert.ToInt16(o.OrderID % 1)) >= 0,
                o => Convert.ToInt64(Convert.ToInt32(o.OrderID % 1)) >= 0,
                o => Convert.ToInt64(Convert.ToInt64(o.OrderID % 1)) >= 0,
                o => Convert.ToInt64(Convert.ToString(o.OrderID % 1)) >= 0
            };

            foreach (var convertMethod in convertMethods)
            {
                await AssertQuery<Order>(
                    isAsync,
                    os => os.Where(o => o.CustomerID == "ALFKI")
                        .Where(convertMethod),
                    entryCount: 6);
            }
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual async Task Convert_ToString(bool isAsync)
        {
            var convertMethods = new List<Expression<Func<Order, bool>>>
            {
                o => Convert.ToString(Convert.ToByte(o.OrderID % 1)) != "10",
                o => Convert.ToString(Convert.ToDecimal(o.OrderID % 1)) != "10",
                o => Convert.ToString(Convert.ToDouble(o.OrderID % 1)) != "10",
                o => Convert.ToString((float)Convert.ToDouble(o.OrderID % 1)) != "10",
                o => Convert.ToString(Convert.ToInt16(o.OrderID % 1)) != "10",
                o => Convert.ToString(Convert.ToInt32(o.OrderID % 1)) != "10",
                o => Convert.ToString(Convert.ToInt64(o.OrderID % 1)) != "10",
                o => Convert.ToString(Convert.ToString(o.OrderID % 1)) != "10",
                o => Convert.ToString(o.OrderDate.Value).Contains("1997") || Convert.ToString(o.OrderDate.Value).Contains("1998")
            };

            foreach (var convertMethod in convertMethods)
            {
                await AssertQuery<Order>(
                    isAsync,
                    os => os.Where(o => o.CustomerID == "ALFKI")
                        .Where(convertMethod),
                    entryCount: 6);
            }
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Indexof_with_emptystring(bool isAsync)
        {
            // ReSharper disable once StringIndexOfIsCultureSpecific.1
            return AssertQueryScalar<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID == "ALFKI").Select(c => c.ContactName.IndexOf(string.Empty)));
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Replace_with_emptystring(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID == "ALFKI").Select(c => c.ContactName.Replace("ari", string.Empty)));
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Substring_with_zero_startindex(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID == "ALFKI").Select(c => c.ContactName.Substring(0, 3)));
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Substring_with_zero_length(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID == "ALFKI").Select(c => c.ContactName.Substring(2, 0)));
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Substring_with_constant(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID == "ALFKI").Select(c => c.ContactName.Substring(1, 3)));
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Substring_with_closure(bool isAsync)
        {
            // ReSharper disable once ConvertToConstant.Local
            var start = 2;

            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID == "ALFKI").Select(c => c.ContactName.Substring(start, 3)));
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Substring_with_client_eval(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.CustomerID == "ALFKI").Select(c => c.ContactName.Substring(c.ContactName.IndexOf('a'), 3)));
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task IsNullOrEmpty_in_predicate(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.IsNullOrEmpty(c.Region)),
                entryCount: 60);
        }

        [ConditionalFact]
        public virtual void IsNullOrEmpty_in_projection()
        {
            using (var context = CreateContext())
            {
                var query = context.Set<Customer>()
                    .Select(
                        c => new
                        {
                            Id = c.CustomerID,
                            Value = string.IsNullOrEmpty(c.Region)
                        })
                    .ToList();

                Assert.Equal(91, query.Count);
            }
        }

        [ConditionalFact]
        public virtual void IsNullOrEmpty_negated_in_projection()
        {
            using (var context = CreateContext())
            {
                var query = context.Set<Customer>()
                    .Select(
                        c => new
                        {
                            Id = c.CustomerID,
                            Value = !string.IsNullOrEmpty(c.Region)
                        })
                    .ToList();

                Assert.Equal(91, query.Count);
            }
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task IsNullOrWhiteSpace_in_predicate(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.IsNullOrWhiteSpace(c.Region)),
                entryCount: 60);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task TrimStart_without_arguments_in_predicate(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactTitle.TrimStart() == "Owner"),
                entryCount: 17);
        }

        [ConditionalTheory(Skip = "Issue #14935. Cannot eval 'where ([c].ContactTitle.TrimStart(O) == \"wner\")'")]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task TrimStart_with_char_argument_in_predicate(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactTitle.TrimStart('O') == "wner"),
                entryCount: 17);
        }

        [ConditionalTheory(Skip = "Issue #14935. Cannot eval 'where ([c].ContactTitle.TrimStart(value(System.Char[])) == \"ner\")'")]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task TrimStart_with_char_array_argument_in_predicate(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactTitle.TrimStart('O', 'w') == "ner"),
                entryCount: 17);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task TrimEnd_without_arguments_in_predicate(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactTitle.TrimEnd() == "Owner"),
                entryCount: 17);
        }

        [ConditionalTheory(Skip = "Issue #14935. Cannot eval 'where ([c].ContactTitle.TrimEnd(r) == \"Owne\")''")]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task TrimEnd_with_char_argument_in_predicate(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactTitle.TrimEnd('r') == "Owne"),
                entryCount: 17);
        }

        [ConditionalTheory(Skip = "Issue #14935. Cannot eval 'where ([c].ContactTitle.TrimEnd(value(System.Char[])) == \"Own\")'")]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task TrimEnd_with_char_array_argument_in_predicate(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactTitle.TrimEnd('e', 'r') == "Own"),
                entryCount: 17);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Trim_without_argument_in_predicate(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactTitle.Trim() == "Owner"),
                entryCount: 17);
        }

        [ConditionalTheory(Skip = "Issue #14935. Cannot eval 'where ([c].ContactTitle.Trim(O) == \"wner\")'")]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Trim_with_char_argument_in_predicate(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactTitle.Trim('O') == "wner"),
                entryCount: 17);
        }

        [ConditionalTheory(Skip = "Issue #14935. Cannot eval 'where ([c].ContactTitle.Trim(value(System.Char[])) == \"wne\")'")]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Trim_with_char_array_argument_in_predicate(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => c.ContactTitle.Trim('O', 'r') == "wne"),
                entryCount: 17);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Order_by_length_twice(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.OrderBy(c => c.CustomerID.Length).ThenBy(c => c.CustomerID.Length).ThenBy(c => c.CustomerID),
                assertOrder: true,
                entryCount: 91);
        }

        // issue #12598
        //[ConditionalTheory]
        //[MemberData(nameof(IsAsyncData))]
        public virtual Task Order_by_length_twice_followed_by_projection_of_naked_collection_navigation(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.OrderBy(c => c.CustomerID.Length).ThenBy(c => c.CustomerID.Length).ThenBy(c => c.CustomerID).Select(c => c.Orders),
                elementAsserter: CollectionAsserter<Order>(o => o.OrderID, (e, a) => Assert.Equal(e.OrderID, a.OrderID)),
                entryCount: 91);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Static_string_equals_in_predicate(bool isAsync)
        {
            return AssertQuery<Customer>(
                isAsync,
                cs => cs.Where(c => string.Equals(c.CustomerID, "ANATR")),
                entryCount: 1);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Static_equals_nullable_datetime_compared_to_non_nullable(bool isAsync)
        {
            var arg = new DateTime(1996, 7, 4);

            return AssertQuery<Order>(
                isAsync,
                os => os.Where(o => Equals(o.OrderDate, arg)),
                entryCount: 1);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Static_equals_int_compared_to_long(bool isAsync)
        {
            long arg = 10248;

            return AssertQuery<Order>(
                isAsync,
                os => os.Where(o => Equals(o.OrderID, arg)));
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Projecting_Math_Truncate_and_ordering_by_it_twice(bool isAsync)
        {
            return AssertQuery<Order>(
                isAsync,
                os => os.Where(o => o.OrderID < 10250).Select(o => new { A = Math.Truncate((double)o.OrderID) }).OrderBy(r => r.A)
                    .OrderBy(r => r.A),
                assertOrder: true);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Projecting_Math_Truncate_and_ordering_by_it_twice2(bool isAsync)
        {
            return AssertQuery<Order>(
                isAsync,
                os => os.Where(o => o.OrderID < 10250).Select(o => new { A = Math.Truncate((double)o.OrderID) }).OrderBy(r => r.A)
                    .OrderByDescending(r => r.A),
                assertOrder: true);
        }

        [ConditionalTheory]
        [MemberData(nameof(IsAsyncData))]
        public virtual Task Projecting_Math_Truncate_and_ordering_by_it_twice3(bool isAsync)
        {
            return AssertQuery<Order>(
                isAsync,
                os => os.Where(o => o.OrderID < 10250).Select(o => new { A = Math.Truncate((double)o.OrderID) }).OrderByDescending(r => r.A)
                    .ThenBy(r => r.A),
                assertOrder: true);
        }
    }
}
